#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/fs.h> /* file_operations */
#include <linux/miscdevice.h>
#include "DeviceStatus.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ryan Welton <Ryan.G.Welton@gmail.com>");
MODULE_DESCRIPTION("Buggered Linux Device for exploitation");
MODULE_VERSION("1.3.3.7");

ssize_t read_from_vuln_device(struct file *filp, char *buf, 
                       size_t count, loff_t *f_pos){
  return 0;
}

ssize_t write_to_vuln_device(struct file *filp, const char * buf, size_t count, loff_t *f_pos)
{
  DeviceStatus stats;
  int ret = copy_from_user(&stats,buf,sizeof(DeviceStatus));
  if(ret){
    printk("Failed to copy %d bytes", ret);
    return ret;
  }
  printk(stats.status);
  return 0;
}

/* Structure that declares the usual file */
/* access functions */
struct file_operations device_ops = {
  read: read_from_vuln_device,
  write: write_to_vuln_device
};

/*
Create our misc device - a char device that doesn't fit into any other device class
http://stackoverflow.com/questions/18456155/what-is-the-difference-between-misc-drivers-and-char-drivers
*/
static struct miscdevice vuln_device = {
        /*
         * We don't care what minor number we end up with, so tell the
         * kernel to just pick one.
         */
        MISC_DYNAMIC_MINOR,
        /*
         * Name ourselves /dev/string_format
         */
        "string_format",
        /*
         * What functions to call when a program performs file
         * operations on the device.
         */
        &device_ops
};

static int __init mod_begin(void)
{
   int ret;
   ret = misc_register(&vuln_device);
   if(ret)
     printk("Failed to register misc device");

   return ret;//A non 0 return means init_module failed; module can't be loaded.
}

static void __exit mod_exit(void)
{
  int ret = misc_deregister(&vuln_device);
  if(ret)
    printk("There was an error unregistering device");
}

module_init(mod_begin);
module_exit(mod_exit);
